package com.mars.push.core.channel.apns;

import com.mars.push.api.dto.PushImMessageInput;
import com.mars.push.core.channel.apns.config.IosPushConfig;
import com.mars.push.core.channel.apns.dto.IosPushType;
import com.mars.push.core.dto.PushMessageType;
import com.turo.pushy.apns.*;
import com.turo.pushy.apns.metrics.micrometer.MicrometerApnsClientMetricsListener;
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
import com.turo.pushy.apns.util.concurrent.PushNotificationFuture;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.Calendar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author King
 * @create 2020/5/25 13:41
 */
@Slf4j
@Component
public class ApplePushServer {

    private static ExecutorService mExecutor;

    static {
        mExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 5, Runtime.getRuntime().availableProcessors() * 5,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }

    private final SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry();
    private final MicrometerApnsClientMetricsListener productMetricsListener =
            new MicrometerApnsClientMetricsListener(meterRegistry,
                    "notifications", "apns_product");
    private final MicrometerApnsClientMetricsListener developMetricsListener =
            new MicrometerApnsClientMetricsListener(meterRegistry,
                    "notifications", "apns_develop");

    private ApnsClient productSvc;
    private ApnsClient developSvc;
    private ApnsClient productVoipSvc;
    private ApnsClient developVoipSvc;

    @Autowired
    private IosPushConfig mConfig;

    @PostConstruct
    private void init() {
//        if (StringUtils.isEmpty(mConfig.getAlert())) {
//            mConfig.setAlert("default");
//        }
//
//        if (StringUtils.isEmpty(mConfig.getVoipAlert())) {
//            mConfig.setAlert("default");
//        }
//
//        try {
//            productSvc = new ApnsClientBuilder()
//                    .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
//                    .setClientCredentials(new File(mConfig.getCerPath()), mConfig.getCerPwd())
//                    .setMetricsListener(productMetricsListener)
//                    .build();
//
//            developSvc = new ApnsClientBuilder()
//                    .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
//                    .setClientCredentials(new File(mConfig.getCerPath()), mConfig.getCerPwd())
//                    .setMetricsListener(developMetricsListener)
//                    .build();
//
//            if (mConfig.isVoipFeature()) {
//                productVoipSvc = new ApnsClientBuilder()
//                        .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
//                        .setClientCredentials(new File(mConfig.getVoipCerPath()), mConfig.getVoipCerPwd())
//                        .setMetricsListener(productMetricsListener)
//                        .build();
//                developSvc = new ApnsClientBuilder()
//                        .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
//                        .setClientCredentials(new File(mConfig.getVoipCerPath()), mConfig.getVoipCerPwd())
//                        .setMetricsListener(developMetricsListener)
//                        .build();
//            }
//
//        } catch (IOException e) {
//            e.printStackTrace();
//            exit(-1);
//        }
    }


    /**
     * 推送消息
     *
     * @param pushMessage
     */
    public void pushMessage(PushImMessageInput pushMessage) {
        final long start = System.currentTimeMillis();
        mExecutor.submit(() -> {
            long now = System.currentTimeMillis();
            if (now - start > 5000) {
                log.error("等待太久，消息抛弃");
                return;
            }
            ApnsClient service;
            if (pushMessage.getPushType() == IosPushType.IOS_PUSH_TYPE_DISTRIBUTION) {
                if (!mConfig.isVoipFeature() || pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL || StringUtils.isEmpty(pushMessage.getVoipDeviceToken())) {
                    service = productSvc;
                } else {
                    service = productVoipSvc;
                }
            } else {
                if (!mConfig.isVoipFeature() || pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL || StringUtils.isEmpty(pushMessage.getVoipDeviceToken())) {
                    service = developSvc;
                } else {
                    service = developVoipSvc;
                }
            }


            if (service == null) {
                log.error("Service not exist!!!!");
                return;
            }
            String sound = mConfig.getAlert();

            String pushContent = pushMessage.getPushContent();
            boolean hiddenDetail = pushMessage.isHiddenDetail();
            if (pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_INVITE) {
                pushContent = "通话邀请";
                sound = mConfig.getVoipAlert();
                hiddenDetail = false;
            } else if (pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_BYE) {
                pushContent = "通话结束";
                sound = null;
                hiddenDetail = false;
            }

            int badge = pushMessage.getUnReceivedMsg();
            if (badge <= 0) {
                badge = 1;
            }

            String title;
            String body;

            if (pushMessage.getConvType() == 1) {
                title = pushMessage.getTargetName();
                if (StringUtils.isEmpty(title)) {
                    title = "群聊";
                }

                if (StringUtils.isEmpty(pushMessage.getSenderName())) {
                    body = pushContent;
                } else {
                    body = pushMessage.getSenderName() + ":" + pushContent;
                }

                if (hiddenDetail) {
                    body = "你收到一条新消息";
                }

                if (pushMessage.getMentionedType() == 1) {
                    if (StringUtils.isEmpty(pushMessage.getSenderName())) {
                        body = "有人在群里@了你";
                    } else {
                        body = pushMessage.getSenderName() + "在群里@了你";
                    }
                } else if (pushMessage.getMentionedType() == 2) {
                    if (StringUtils.isEmpty(pushMessage.getSenderName())) {
                        body = "有人在群里@了大家";
                    } else {
                        body = pushMessage.getSenderName() + "在群里@了大家";
                    }
                }
            } else {
                if (pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_FRIEND_REQUEST) {
                    if (StringUtils.isEmpty(pushMessage.getSenderName())) {
                        title = "好友请求";
                    } else {
                        title = pushMessage.getSenderName() + " 请求加您为好友";
                    }
                } else {
                    if (StringUtils.isEmpty(pushMessage.getSenderName())) {
                        title = "消息";
                    } else {
                        title = pushMessage.getSenderName();
                    }
                }

                if (hiddenDetail) {
                    body = "你收到一条新消息";
                } else {
                    body = pushContent;
                }
            }

            final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
            payloadBuilder.setAlertBody(body);
            payloadBuilder.setAlertTitle(title);
            payloadBuilder.setBadgeNumber(badge);
            payloadBuilder.setSound(sound);

            final String payload = payloadBuilder.buildWithDefaultMaximumLength();
            final String token;
            if (service == productVoipSvc || service == developVoipSvc) {
                token = pushMessage.getVoipDeviceToken();
            } else {
                token = pushMessage.getDeviceToken();
            }

            Calendar c = Calendar.getInstance();


            ApnsPushNotification pushNotification;

            if (!mConfig.isVoipFeature() || pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL || StringUtils.isEmpty(pushMessage.getVoipDeviceToken())) {
                if (pushMessage.getPushMessageType() == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL || StringUtils.isEmpty(pushMessage.getVoipDeviceToken())) {
                    c.add(Calendar.MINUTE, 10); //普通推送
                    pushNotification = new SimpleApnsPushNotification(token, pushMessage.getPackageName(), payload, c.getTime(), DeliveryPriority.CONSERVE_POWER, PushType.ALERT);
                } else {
                    c.add(Calendar.MINUTE, 1); //voip通知，使用普通推送
                    pushNotification = new SimpleApnsPushNotification(token, pushMessage.getPackageName(), payload, c.getTime(), DeliveryPriority.IMMEDIATE, PushType.ALERT);
                }

            } else {
                c.add(Calendar.MINUTE, 1);
                pushNotification = new SimpleApnsPushNotification(token, pushMessage.getPackageName() + ".voip", payload, c.getTime(), DeliveryPriority.IMMEDIATE, PushType.VOIP);
            }


            final PushNotificationFuture<ApnsPushNotification, PushNotificationResponse<ApnsPushNotification>>
                    sendNotificationFuture = service.sendNotification(pushNotification);
            sendNotificationFuture.addListener(new GenericFutureListener<Future<? super PushNotificationResponse<ApnsPushNotification>>>() {
                @Override
                public void operationComplete(Future<? super PushNotificationResponse<ApnsPushNotification>> future) throws Exception {

                    if (future.isSuccess()) {
                        final PushNotificationResponse<ApnsPushNotification> pushNotificationResponse =
                                sendNotificationFuture.getNow();
                    } else {
                        future.cause().printStackTrace();
                    }
                }
            });
        });

    }


}
